package sxe.core.cs511.team2_2;

import java.util.*;
import snobject.*;
import step.EvaluationFailure;
import step.FunctionWrapper;
import java.awt.image.BufferedImage;
import org.jfree.chart.*;
import org.jfree.data.time.*;

/** OVERVIEW:  A class that defines the opcode makegraph.
 *  The abstraction function is AF(c) = {title, x axis label, y axis label, a collection of data elements, each containing an x and y element}
 *  The representation invariant is that snStruct, if non-null, must contain a collection of snPair elements.  
 * @author lisap
 *
 */

public class makegraph extends FunctionWrapper {	
	private String xAxisLabel;
	private String yAxisLabel;
	private String title;
	private snStruct data;
	private JFreeChart chart = null;
	private TimeSeriesCollection tsdata = new TimeSeriesCollection();
	private TimeSeries series = new TimeSeries("a series", Millisecond.class);

	/** EFFECTS:  This method takes a graph title, xaxis label, yaxis label, and an snStruct containing snPair objects and returns a graphical representation of the snPair objects.
	 * The left snPair elements represent x-axis data items and the right snPair elements represent y-axis data items.
	 * The min and max axes limits are determined by the min and max of the data elements.
	 * This method is called when this opcode is called in a STEP program.
	 * @param arg a list of arguments:  title, xaxis label, yaxis label, and snStruct containing snPairs as values (keys don't matter)
	 * @return a graphical representation of the Table, as an snImage
	 * @throws EvaluationFailure
	 */
	public snObject Call(snObjectArgList arg) throws EvaluationFailure {
		title = arg.popString().getString();
		xAxisLabel = arg.popString().getString();
		yAxisLabel = arg.popString().getString();
		data = arg.popStruct();
		Collection col = data.getValues();
		Iterator it = col.iterator();
		
		while (it.hasNext()){
			snPair apair = null;
			try{
				apair = (snPair)it.next();
			} catch (ClassCastException e){
				System.err.println("makegraph expects snPair objects in snStruct supplied as the data");
				throw new EvaluationFailure(this.expnode, "makegraph expects snPair objects in snStruct supplied as the data");
			}
			if (apair != null){
				Date adate = new Date((long)((snDouble)apair.getLeft()).getDbl());
				RegularTimePeriod time = RegularTimePeriod.createInstance(Millisecond.class, adate, RegularTimePeriod.DEFAULT_TIME_ZONE);

				// add this entry to the series
				series.add(time, (double)((snInteger)apair.getRight()).getInt());
				
				// approx 4 hours of data at a time.
				series.setMaximumItemCount(28800);
				
				// add this series to the series collection (weird, I know)
				if(chart==null)
					tsdata.addSeries(series);
			}
		}
		
		// create the chart if not created (updates handled by the series.add above)
		if(chart==null){
			chart = ChartFactory.createTimeSeriesChart(title, // title
					xAxisLabel, // X-axis label
					yAxisLabel, // Y-axis label
					tsdata, // Get Data.
					false, // Create legend?
					false, // Generate tooltips?
					false // Generate URLs?
					);
		}

		BufferedImage bi = chart.createBufferedImage(500, 300);
				    
		return new snImage(bi);
	}
}
